﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

using SmlEngine;
using SmlEngine.Graphics;
using SmlEngine.IO;
using SmlEngine.Extensions;
using SmlEngine.Sprites.Base;
using SmlEngine.Sprites.Base.WorldMap;

namespace SmlEngine.Sprites.Base.WorldMap
{
    public class SMB3LevelTile : LevelTile, IWorldDrawable
    {
        #region Fields and Properties
        // textures
        public WorldTile LockedTile { get; private set; }
        public WorldTile UnlockingTile { get; private set; }
        public WorldTile UnlockedTile { get; private set; }

        private UnlockedGraphicsType type = UnlockedGraphicsType.Static;
        private int unlockedDrawFrameIndex;

        public LockedState LockState { get; private set; }

        public override int exitNumber
        {
            get { return -1; }
        }

        public override bool IsRevealed
        {
            get { return true; }
        }

        public override Vector2 Size
        {
            get
            {
                return LockedTile.Size;
            }
        }

        public override bool IsNode
        {
            get
            {
                return true;
            }
        }

        #region Number Overlay Constants

        private Vector2 overlaySize = new Vector2(16, 16);
        private Vector2[] overlaysPositions = new Vector2[10] 
        { 
            new Vector2(16, 16), new Vector2(32, 16), new Vector2(48, 16),
            new Vector2(64, 16), new Vector2(80, 16), new Vector2(96, 16), new Vector2(112, 16), new Vector2(0, 32), new Vector2(16, 32),
            new Vector2(32, 32)
        };

        #endregion


        #endregion

        #region Methods

        #region Constructors and Content Loading

        public SMB3LevelTile(GraphicsDevice gd, ContentManager cm, string source, List<Rectangle> lockedSourceRects, List<Rectangle> unlockingSourceRects,
            List<Rectangle> unlockedSourceRects, UnlockedGraphicsType cType, int frameTime)
        {
            LockedTile = new WorldTile(source, lockedSourceRects);
            UnlockingTile = new WorldTile(source, unlockingSourceRects);
            UnlockedTile = new WorldTile(source, unlockedSourceRects);
            type = cType;

            LockedTile.SetData(frameTime);
            UnlockingTile.SetData(frameTime);
            UnlockedTile.SetData(frameTime);

            //LoadContent(gd, cm);
            UnlockingTile.Stop(); // delay animation until we're unlocking
        }

        public new void LoadContent(GraphicsDevice gd, ContentManager cm)
        {
            LockedTile.LoadContent(gd, cm, LockedTile.HasMultipleFrames);
            UnlockingTile.LoadContent(gd, cm, UnlockingTile.HasMultipleFrames);
            UnlockedTile.LoadContent(gd, cm, type == UnlockedGraphicsType.Animated);
        }

        public override void UnloadContent()
        {
            LockedTile.UnloadContent();
            UnlockingTile.UnloadContent();
            UnlockedTile.UnloadContent();
        }

        /// <summary>
        /// Draws a number over the level tile.
        /// </summary>
        /// <param name="cm">The ContentMananger to use.</param>
        /// <param name="number">The one-based number to draw (corresponds to the actual number).</param>
        public void OverlayNumber(ContentManager cm, int number)
        {
            number--;
            LockedTile.Overlay(cm, @"world\ow_level", overlaysPositions[number].ToRectangle(overlaySize));
        }
        #endregion

        #region Update and Draw
        public override void Draw(GameTime gameTime, SpriteBatch spriteBatch)
        {
            switch (LockState)
            {
                case LockedState.Locked:
                    LockedTile.Draw(gameTime, spriteBatch, Position);
                    break;
                case LockedState.Unlocking:
                    UnlockingTile.Draw(gameTime, spriteBatch, Position);
                    if (!UnlockingTile.isRunningOnce && !UnlockingTile.HasAnimationEnded)
                    {
                        UnlockingTile.PlayOnce();
                    }
                    else
                    {
                        if (UnlockingTile.HasAnimationEnded)
                        {
                            LockState = LockedState.Unlocked;
                            DrawUnlockedTile(gameTime, spriteBatch);
                            return;
                        }
                    }
                    //UnlockingTile.Draw(gameTime, spriteBatch, Position);
                    break;
                case LockedState.Unlocked:
                    DrawUnlockedTile(gameTime, spriteBatch);
                    break;
                default:
                    break;
            }
        }

        public override void Update(GameTime gameTime) { }

        private void DrawUnlockedTile(GameTime gameTime, SpriteBatch spriteBatch)
        {
            if (!UnlockedTile.isAnimated)
            {
                UnlockedTile.Draw(gameTime, spriteBatch, unlockedDrawFrameIndex, Position);
            }
            else
            {
                UnlockedTile.Draw(gameTime, spriteBatch, Position);
            }
        }

        public void Unlock()
        {
            LockState = LockedState.Unlocking;
        }

        public void Unlock(int frameIndex)
        {
            LockState = LockedState.Unlocking;
            unlockedDrawFrameIndex = frameIndex;
        }
        #endregion

        public void SetData(Vector2 position, string levelDisplayName, string levelFileName)
        {
            base.SetData(position, levelDisplayName, levelFileName, new List<Exit>());
            LockedTile.SetData(Position);
            UnlockingTile.SetData(Position);
            UnlockedTile.SetData(Position);
        }

        #endregion
    }

    public enum UnlockedGraphicsType
    {
        /// <summary>
        /// A static unlocked graphic is like the M-symbol for when Mario clears a level.
        /// The unlockedFrames list contains a list of textures, but only one is drawn.
        /// </summary>
        Static,
        /// <summary>
        /// The unlockedFrame list contains a list of textures which are drawn in order.
        /// </summary>
        Animated
    }

    public enum LockedState
    {
        Locked,
        Unlocking,
        Unlocked
    }
}
